package com.xwaiy.xwaiyrpc.proxy;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.xwaiy.xwaiyrpc.RpcApplication;
import com.xwaiy.xwaiyrpc.config.RpcConfig;
import com.xwaiy.xwaiyrpc.constant.RpcConstant;
import com.xwaiy.xwaiyrpc.exception.RpcException;
import com.xwaiy.xwaiyrpc.exception.enums.ErrorCode;
import com.xwaiy.xwaiyrpc.fault.retry.RetryStrategy;
import com.xwaiy.xwaiyrpc.fault.retry.RetryStrategyFactory;
import com.xwaiy.xwaiyrpc.fault.tolerant.TolerantStrategy;
import com.xwaiy.xwaiyrpc.fault.tolerant.TolerantStrategyFactory;
import com.xwaiy.xwaiyrpc.loadbalancer.LoadBalancer;
import com.xwaiy.xwaiyrpc.loadbalancer.LoadBalancerFactory;
import com.xwaiy.xwaiyrpc.model.RpcRequest;
import com.xwaiy.xwaiyrpc.model.RpcResponse;
import com.xwaiy.xwaiyrpc.model.ServiceMetaInfo;
import com.xwaiy.xwaiyrpc.protocol.*;
import com.xwaiy.xwaiyrpc.registry.Registry;
import com.xwaiy.xwaiyrpc.registry.RegistryFactory;
import com.xwaiy.xwaiyrpc.serializer.JdkSerializer;
import com.xwaiy.xwaiyrpc.serializer.Serializer;
import com.xwaiy.xwaiyrpc.serializer.SerializerFactory;
import com.xwaiy.xwaiyrpc.server.tcp.VertxTcpClient;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetClient;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 服务代理（动态）
 * @Author Xwaiy
 * @Date 2025/8/21 16:17
 **/
public class ServiceProxy implements InvocationHandler {
    /**
     * 调用代理
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 构造请求
        String serviceName = method.getDeclaringClass().getName();

        RpcRequest rpcReq = RpcRequest.builder()
                .serviceName(serviceName)
                .methodName(method.getName())
                .paramTypes(method.getParameterTypes())
                .params(args).build();

        // 发送请求
        RpcConfig rpcConfig = RpcApplication.getRpcConfig();
        Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getRegistry());
        ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
        serviceMetaInfo.setServiceName(serviceName);

        serviceMetaInfo.setVersion(RpcConstant.DEFAULT_SERVICE_VERSION);
        List<ServiceMetaInfo> list = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());

        if(CollUtil.isEmpty(list)) {
            throw new RpcException(ErrorCode.CONSUMER_SERVICE_NOT_FOUND, "暂无服务地址");
        }

        LoadBalancer loadBalancer = LoadBalancerFactory.getInstance(rpcConfig.getLoadBalancer());
        Map<String, Object> params = new HashMap<>();
        params.put("method",rpcReq.getMethodName());
        ServiceMetaInfo selected = loadBalancer.select(params,list);

        RpcResponse rpcResp;
        try {
            // 发送请求 TCP（使用重试机制）
            RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(rpcConfig.getRetryStrategy());

            rpcResp = retryStrategy.doRetry(()->
                VertxTcpClient.doRequest(rpcReq,selected)
            );
        } catch (Exception e) {
            // DONE 使用 Fail-Back 容错机制
            Map<String, Object> context = new HashMap<>();
            context.put("request", rpcReq);
            context.put("selectedService", selected);
            context.put("serviceList", list);

            TolerantStrategy tolerantStrategy = TolerantStrategyFactory.getInstance(rpcConfig.getTolerantStrategy());
            rpcResp = tolerantStrategy.doTolerant(context, e);
        }
        return rpcResp.getData();
    }
}
